// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_tool_scale.h"
#include "mk_engine.h"
#include "mk_painter.h"
#include "mk_camera.h"
#include "mk_engine.h"
#include "mk_render_window.h"
#include "mk_error.h"
#include "mk_math.h"

namespace MK3DE
{
	const float __JUDGE_RANGE_SQ = 25.0f;

	CToolScale* CToolScale::Create()
	{
		return new CToolScale();
	}

	void CToolScale::Destroy(CToolScale* tool)
	{
		delete tool;
	}

	CToolScale::CToolScale()
	{
		_x = 0;
		_y = 0;
		_z = 0;
		_length = 10.0f;
		_sx = 0;
		_sy = 0;
		_sz = 0;
		_bSelected = FALSE;
		_currentAxis = AXIS_NONE;
		_bEnable = TRUE;
	}

	CToolScale::~CToolScale()
	{

	}

	void CToolScale::Render()
	{
		if (!_bEnable)
			return;

		CPainter* painter = GetEngine()->GetPainter();

		if (_currentAxis == AXIS_X || _currentAxis == AXIS_XYZ)
			painter->DrawLine3D(D3DXVECTOR3(_x, _y, _z), D3DXVECTOR3(_x + _length, _y, _z), 0xffffff00, 0xffffff00);
		else
			painter->DrawLine3D(D3DXVECTOR3(_x, _y, _z), D3DXVECTOR3(_x + _length, _y, _z), 0xffff0000, 0xffff0000);

		if (_currentAxis == AXIS_Y || _currentAxis == AXIS_XYZ)
			painter->DrawLine3D(D3DXVECTOR3(_x, _y, _z), D3DXVECTOR3(_x, _y + _length, _z), 0xffffff00, 0xffffff00);
		else
			painter->DrawLine3D(D3DXVECTOR3(_x, _y, _z), D3DXVECTOR3(_x, _y + _length, _z), 0xff00ff00, 0xff00ff00);

		if (_currentAxis == AXIS_Z || _currentAxis == AXIS_XYZ)
			painter->DrawLine3D(D3DXVECTOR3(_x, _y, _z), D3DXVECTOR3(_x, _y, _z + _length), 0xffffff00, 0xffffff00);
		else
			painter->DrawLine3D(D3DXVECTOR3(_x, _y, _z), D3DXVECTOR3(_x, _y, _z + _length), 0xff0000ff, 0xff0000ff);

		if (_currentAxis == AXIS_XYZ)
		{
			painter->DrawLine3D(D3DXVECTOR3(_x + _length * 0.3f, _y, _z), D3DXVECTOR3(_x, _y + _length * 0.3f, _z), 0xffffff00, 0xffffff00);
			painter->DrawLine3D(D3DXVECTOR3(_x + _length * 0.3f, _y, _z), D3DXVECTOR3(_x, _y, _z + _length * 0.3f), 0xffffff00, 0xffffff00);
			painter->DrawLine3D(D3DXVECTOR3(_x, _y + _length * 0.3f, _z), D3DXVECTOR3(_x, _y, _z + _length * 0.3f), 0xffffff00, 0xffffff00);
		}
		else
		{
			painter->DrawLine3D(D3DXVECTOR3(_x + _length * 0.3f, _y, _z), D3DXVECTOR3(_x, _y + _length * 0.3f, _z), 0xffff0000, 0xff00ff00);
			painter->DrawLine3D(D3DXVECTOR3(_x + _length * 0.3f, _y, _z), D3DXVECTOR3(_x, _y, _z + _length * 0.3f), 0xffff0000, 0xff0000ff);
			painter->DrawLine3D(D3DXVECTOR3(_x, _y + _length * 0.3f, _z), D3DXVECTOR3(_x, _y, _z + _length * 0.3f), 0xff00ff00, 0xff0000ff);
		}
	}

	void CToolScale::SetPosition(float x, float y, float z)
	{
		_x = x;
		_y = y;
		_z = z;

		_sx = 0;
		_sy = 0;
		_sz = 0;

		_bSelected = FALSE;
		_currentAxis = AXIS_NONE;
	}

	void CToolScale::GetScale(float& x, float& y, float& z)
	{
		x = _sx;
		y = _sy;
		z = _sz;
	}

	BOOL CToolScale::OnMouseLeftDown(float x, float y)
	{
		if (!_bEnable)
			return FALSE;

		if (_currentAxis == AXIS_NONE)
			return FALSE;

		_lastPos.x = x;
		_lastPos.y = y;
		_bSelected = TRUE;

		return TRUE;
	}

	void CToolScale::Update()
	{
		if (!_bEnable)
			return;

		D3DXVECTOR3 pos(_x, _y, _z);
		CCamera* cam = GetEngine()->GetCurrentCamera();
		float n = cam->GetViewNear();
		float f = cam->GetViewFar();
		D3DXVec3TransformCoord(&pos, &pos, &cam->GetViewMatrix());
		_length = pos.z * 0.1f;
	}

	BOOL CToolScale::OnMouseMove(float x, float y)
	{
		if (!_bEnable)
			return FALSE;

		CCamera* cam = GetEngine()->GetCurrentCamera();
		CRenderWindow* win = GetEngine()->GetCurrentRenderWindow();

		if (_bSelected)
		{
			assert(_currentAxis != AXIS_NONE);

			if (_currentAxis == AXIS_XYZ)
			{
				float dis = _lastPos.y - y;
				_sx += dis * 0.1f;
				_sy += dis * 0.1f;
				_sz += dis * 0.1f;
			}
			else
			{
				D3DXVECTOR2 pos1, pos2;
				cam->ProjectPoint(pos1, D3DXVECTOR3(_x, _y, _z), win->GetWidth(), win->GetHeight());
				if (_currentAxis == AXIS_X)
					cam->ProjectPoint(pos2, D3DXVECTOR3(_x + _length, _y, _z), win->GetWidth(), win->GetHeight());
				else if (_currentAxis == AXIS_Y)
					cam->ProjectPoint(pos2, D3DXVECTOR3(_x, _y + _length, _z), win->GetWidth(), win->GetHeight());
				else if (_currentAxis == AXIS_Z)
					cam->ProjectPoint(pos2, D3DXVECTOR3(_x, _y, _z + _length), win->GetWidth(), win->GetHeight());

				D3DXVECTOR2 A = pos2 - pos1;
				D3DXVECTOR2 B(x - _lastPos.x, y - _lastPos.y);
				float lenA = D3DXVec2Length(&A);
				float lenB = D3DXVec2Length(&B);
				D3DXVec2Normalize(&A, &A);
				D3DXVec2Normalize(&B, &B);
				float dot = D3DXVec2Dot(&A, &B);
				float dis = dot * lenB * _length / lenA;

				if (_currentAxis == AXIS_X)
					_sx += dis * 0.1f;
				else if (_currentAxis == AXIS_Y)
					_sy += dis * 0.1f;
				else if (_currentAxis == AXIS_Z)
					_sz += dis * 0.1f;
			}

			_lastPos.x = x;
			_lastPos.y = y;
		}
		else
		{
			D3DXVECTOR2 pos, posX, posY, posZ, posXX, posYY, posZZ;
			cam->ProjectPoint(pos, D3DXVECTOR3(_x, _y, _z), win->GetWidth(), win->GetHeight());
			cam->ProjectPoint(posX, D3DXVECTOR3(_x + _length, _y, _z), win->GetWidth(), win->GetHeight());
			cam->ProjectPoint(posY, D3DXVECTOR3(_x, _y + _length, _z), win->GetWidth(), win->GetHeight());
			cam->ProjectPoint(posZ, D3DXVECTOR3(_x, _y, _z + _length), win->GetWidth(), win->GetHeight());
			cam->ProjectPoint(posXX, D3DXVECTOR3(_x + _length * 0.3f, _y, _z), win->GetWidth(), win->GetHeight());
			cam->ProjectPoint(posYY, D3DXVECTOR3(_x, _y + _length * 0.3f, _z), win->GetWidth(), win->GetHeight());
			cam->ProjectPoint(posZZ, D3DXVECTOR3(_x, _y, _z + _length * 0.3f), win->GetWidth(), win->GetHeight());

			if (IsPointNearSegment(pos, posX, x, y, __JUDGE_RANGE_SQ))
				_currentAxis = AXIS_X;
			else if (IsPointNearSegment(pos, posY, x, y, __JUDGE_RANGE_SQ))
				_currentAxis = AXIS_Y;
			else if (IsPointNearSegment(pos, posZ, x, y, __JUDGE_RANGE_SQ))
				_currentAxis = AXIS_Z;
			else if (IsPointNearSegment(posXX, posYY, x, y, __JUDGE_RANGE_SQ) ||
				IsPointNearSegment(posXX, posZZ, x, y, __JUDGE_RANGE_SQ) ||
				IsPointNearSegment(posYY, posZZ, x, y, __JUDGE_RANGE_SQ))
				_currentAxis = AXIS_XYZ;
			else
				_currentAxis = AXIS_NONE;
		}

		return TRUE;
	}


	BOOL CToolScale::OnMouseLeftUp(float x, float y)
	{
		if (!_bEnable)
			return FALSE;

		_bSelected = FALSE;
		return TRUE;
	}

}